<template>
    <div class="tools-aiChat-page _page">
        <HistoryList ref="historyListEl" @switchtopic="doSwitchTopic"/>
        <div class="chat-wrap">
            <MessageList ref="messageListEl" :datas="messageDatas" @stop="doStopCurrAiChat"/>
            <ChatInput @newtopic="doStartNewTopic('')" @send="doSend" ref="chatInputEl"/>
            <div class="chat-tips">内容由AI生成，无法确保真实准确，仅供参考</div>
        </div>
    </div>
</template>

<script>
import HistoryList from './historyList/Main.vue'
import MessageList from './messageList/Main.vue'
import ChatInput from './chatInput/Main.vue'
import { askQuestion } from './request'
import { parseMultiJson } from './util'
import { uuid } from '@/lib/util'
import { ref } from 'vue'
import { useToastStore } from '@/stores/toast'

export default {
    components: {
        HistoryList, MessageList, ChatInput
    },
    setup () {
        const toast = useToastStore()
        const messageDatas = ref([])
        const chatInputEl = ref(null)
        const historyListEl = ref(null)
        const messageListEl = ref(null)
        const isInGenerating = ref(false) // 是否正在生成中
        let abortController = null
        let currTopicId = uuid() // 当前话题ID

        const saveCurrMessageDatas = () => {
            let historyDatas = localStorage.getItem('AiHistoryChatDatas')
            if (historyDatas) {
                historyDatas = JSON.parse(historyDatas)
            } else {
                historyDatas = []
            }
            if (messageDatas.value.length > 0) {
                const findObj = historyDatas.find(item => item.id === currTopicId)
                if (findObj) {
                    findObj.datas = [...messageDatas.value]
                } else {
                    historyDatas.unshift({
                        id: currTopicId,
                        title: messageDatas.value[0].content,
                        datas: [...messageDatas.value]
                    })
                }
            }
            if (historyDatas.length) {
                localStorage.setItem('AiHistoryChatDatas', JSON.stringify(historyDatas))
                historyListEl.value.refresh()
            }
        }

        const readData = (reader, decoder, buffer) => {
            return reader.read().then(({ done, value }) => {
                if (done) {
                    // console.log('done...', buffer)
                    const lastMsg = messageDatas.value[messageDatas.value.length - 1]
                    lastMsg.isFinished = true
                    isInGenerating.value = false
                    abortController = null
                    saveCurrMessageDatas()
                    return buffer
                }
                const chunk = decoder.decode(value, { stream: true })
                const chunkDatas = parseMultiJson(chunk)
                // console.log('chunkDatas...', chunkDatas)
                const lastMsg = messageDatas.value[messageDatas.value.length - 1]
                chunkDatas.forEach(item => {
                    item.choices.forEach(choice => {
                        if (choice.delta.content) {
                            lastMsg.content += choice.delta.content
                        } else if (choice.delta.reasoning_content) {
                            lastMsg.thinkContent += choice.delta.reasoning_content
                        }
                    })
                })
                buffer.push(...chunkDatas)
                messageListEl.value.doScrollBottom()
                return readData(reader, decoder, buffer)
            })
        }

        const doSend = (question) => {
            if (isInGenerating.value) {
                toast.warning('请等待回答完毕！')
                return
            }
            // console.log('question', question)
            messageDatas.value.push({
                role: 'user',
                content: question
            })
            const answer = {
                role: 'system',
                content: '',
                thinkContent: '',
                isFinished: false
            }
            messageDatas.value.push(answer)
            chatInputEl.value.doClearQuestion()
            isInGenerating.value = true
            abortController = new AbortController()
            const signal = abortController.signal
            saveCurrMessageDatas()
            messageListEl.value.doScrollBottom()
            askQuestion(messageDatas.value, signal).then(response => {
                const decoder = new TextDecoder('utf-8')
                let buffer = []
                const reader = response.body.getReader()
                return readData(reader, decoder, buffer)
            }).catch(error => {
                // console.log('error', error)
                if (error.name === 'AbortError') {
                    // console.log('取消了请求......')
                    isInGenerating.value = false
                    abortController = null
                    const lastMsg = messageDatas.value[messageDatas.value.length - 1]
                    lastMsg.isFinished = true
                    saveCurrMessageDatas()
                }
            })
        }

        const doStopCurrAiChat = () => {
            if (abortController) {
                abortController.abort()
            }
        }

        const doStartNewTopic = (topicId = '') => {
            if (isInGenerating.value) {
                toast.warning('请等待回答完毕或者您停止生成！')
                return
            }
            let historyDatas = localStorage.getItem('AiHistoryChatDatas')
            if (historyDatas) {
                historyDatas = JSON.parse(historyDatas)
            } else {
                historyDatas = []
            }
            saveCurrMessageDatas()
            if (topicId) {
                currTopicId = topicId
                const findObj = historyDatas.find(item => item.id === currTopicId)
                messageDatas.value = findObj.datas
            } else {
                messageDatas.value = []
                currTopicId = uuid()
            }
            chatInputEl.value.doClearQuestion()
            abortController = null
        }

        const doSwitchTopic = (topicId) => {
            if (currTopicId == topicId) {
                return
            }
            if (isInGenerating.value) {
                doStopCurrAiChat() // 停止当前对话
            }
            setTimeout(() => {
                doStartNewTopic(topicId)
            }, 1000)
        }

        return {
            messageDatas,
            chatInputEl,
            historyListEl,
            messageListEl,
            doSend,
            isInGenerating,
            doStopCurrAiChat,
            doStartNewTopic,
            doSwitchTopic
        }
    }
}
</script>

<style lang="scss">
    @use './style.scss';
</style>
